package com.hexinfo.dmpro.component.file.transfer.service.impl;

import cn.hutool.core.util.StrUtil;
import com.hexinfo.dmpro.component.file.transfer.service.ScpTransferService;
import com.jcraft.jsch.*;
import liquibase.util.file.FilenameUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Vector;

@Slf4j
@Service
public class ScpTransferServiceImpl implements ScpTransferService {

    /**
     * @Method getSession
     * @Param
     * @Return com.jcraft.jsch.Session
     * @Description 获取session
     * @Author Wang zhihao
     * @Date 2023/11/21 19:10
     * @Version V1.0
     */
    @Override
    public Session getSession(String host, int port, String user, String password) {
        JSch jSch = new JSch();
        Session session = null;
        try {
            session = jSch.getSession(user,host,port);
            session.setPassword(password);
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();
        } catch (Exception e) {
            log.error(StrUtil.format("获取session异常: 信息为 [host: {}, port: {}, username: {}, password: {}]", host, port, user, password) + e.getMessage());
            throw new RuntimeException("获取session异常" + e.getMessage());
        }
        return session;
    }

    /**
     * @Method removeFile
     * @Param
     * @Return void
     * @Description 删除文件
     * @Author Wang zhihao
     * @Date 2023/11/21 19:10
     * @Version V1.0
     */
    @Override
    public void removeFile(Session session, String filePath) {
        Channel channel = null;
        try {
            channel = session.openChannel("exec");
            ((ChannelExec) channel).setCommand("rm " + filePath);
            channel.setInputStream(null);
            ((ChannelExec) channel).setErrStream(System.err);
            channel.connect();
        } catch (Exception e) {
            log.error("删除文件" + e.getMessage());
            throw new RuntimeException("删除文件" + e.getMessage());
        } finally {
            channel.disconnect();
        }
    }

    /**
     * @Method removeDir
     * @Param
     * @Return void
     * @Description 删除目录
     * @Author Wang zhihao
     * @Date 2023/11/21 19:10
     * @Version V1.0
     */
    @Override
    public void removeDir(Session session, String fileDir) {
        Channel channel = null;
        try {
            channel = session.openChannel("exec");
            ((ChannelExec) channel).setCommand("rm -r " + fileDir);
            channel.setInputStream(null);
            ((ChannelExec) channel).setErrStream(System.err);
            channel.connect();
        } catch (Exception e) {
            log.error("删除目录" + e.getMessage());
            throw new RuntimeException("删除目录" + e.getMessage());
        } finally {
            channel.disconnect();
        }
    }

    /**
     * @Method createDir
     * @Param
     * @Return void
     * @Description 多层级创建目录
     * @Author Wang zhihao
     * @Date 2023/11/21 20:23
     * @Version V1.0
     */
    @Override
    public void createDir(Session session, String dir) {
        Channel channel = null;
        try {
            channel = session.openChannel("exec");
            ((ChannelExec) channel).setCommand("mkdir -p " + dir);
            channel.setInputStream(null);
            ((ChannelExec) channel).setErrStream(System.err);
            channel.connect();
        } catch (Exception e) {
            log.error("创建目录报错" + e.getMessage());
            throw new RuntimeException("创建目录报错" + e.getMessage());
        } finally {
            channel.disconnect();
        }
    }

    /**
     * @Method moveFile
     * @Param
     * @Return void
     * @Description 移动文件
     * @Author Wang zhihao
     * @Date 2023/11/21 19:11
     * @Version V1.0
     */
    @Override
    public void moveFile(Session session, String remoteFilePath, String newRemoteFilDir, String fileName) {
        Channel channel = null;
        try {
            if (!isExistsDir(session, newRemoteFilDir)) {
                createDir(session, newRemoteFilDir);
            }
            channel = session.openChannel("exec");
            ((ChannelExec) channel).setCommand("mv " + remoteFilePath + " " + newRemoteFilDir + fileName);
            channel.setInputStream(null);
            ((ChannelExec) channel).setErrStream(System.err);
            channel.connect();
        } catch (Exception e) {
            log.error("文件移动报错" + e.getMessage());
            throw new RuntimeException("文件移动报错" + e.getMessage());
        } finally {
            channel.disconnect();
        }
    }

    /**
     * @Method uploadFile
     * @Param
     * @Return void
     * @Description 上传文件
     * @Author Wang zhihao
     * @Date 2023/11/21 13:25
     * @Version V1.0
     */
    @Override
    public void uploadFile(Session session, String localFilePath, String remoteFilePath, String fileName) {
        Channel channel = null;
        ChannelSftp sftpChannel = null;
        try {
            channel = session.openChannel("sftp");
            channel.connect();
            // 上传文件
            sftpChannel = (ChannelSftp) channel;
            sftpChannel.put(localFilePath, remoteFilePath);
            sftpChannel.exit();
        } catch (Exception e) {
            System.out.println("上传文件报错" + e.getMessage());
            throw new RuntimeException("上传文件报错" + e.getMessage());
        } finally {
            channel.disconnect();
        }
    }

    /**
     * @Method downloadFile
     * @Param
     * @Return void
     * @Description 下载文件
     * @Author Wang zhihao
     * @Date 2023/11/21 13:25
     * @Version V1.0
     */
    @Override
    public void downloadFile(Session session, String localFilePath, String remoteFilePath, String fileName) {
        Channel channel = null;
        ChannelSftp sftpChannel = null;
        InputStream inputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            channel = session.openChannel("sftp");
            channel.connect();
            sftpChannel = (ChannelSftp) channel;
            inputStream = sftpChannel.get(remoteFilePath);
           fileOutputStream = new FileOutputStream(localFilePath + "/" + fileName);
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, bytesRead);
            }
        } catch (Exception e) {
            System.out.println("下载文件报错" + e.getMessage());
            throw new RuntimeException("下载文件报错" + e.getMessage());
        } finally {
            try {
                inputStream.close();
                fileOutputStream.close();
                sftpChannel.exit();
                channel.disconnect();
            } catch (Exception e) {
                log.error("下载文件关闭连接报错: " + e.getMessage(), e);
                throw new RuntimeException("下载文件关闭连接报错: " + e.getMessage(), e);
            }
        }
    }

    /**
     * @Method isExistsDir
     * @Param
     * @Return boolean
     * @Description 校验目录是否存在
     * @Author Wang zhihao
     * @Date 2023/11/21 19:11
     * @Version V1.0
     */
    @Override
    public boolean isExistsDir(Session session, String fileDir) {
        ChannelSftp sftpChannel = null;
        try {
            sftpChannel = (ChannelSftp) session.openChannel("sftp");
            sftpChannel.connect();
            // 获取文件列表
            Vector<ChannelSftp.LsEntry> files = sftpChannel.ls(fileDir);
            return true;
        } catch (Exception e) {
            log.error("校验文件夹" + fileDir + "不存在");
            return false;
        } finally {
            sftpChannel.disconnect();
        }
    }

    /**
     * @Method isExistsPath
     * @Param
     * @Return boolean
     * @Description 校验文件是否存在
     * @Author Wang zhihao
     * @Date 2023/11/21 19:11
     * @Version V1.0
     */
    @Override
    public boolean isExistsPath(Session session, String filePath) {
        ChannelSftp sftpChannel = null;
        try {
            boolean isExists = false;
            String fileName = FilenameUtils.getName(filePath);
            String fileDir = StrUtil.removeAll(filePath, fileName);
            sftpChannel = (ChannelSftp) session.openChannel("sftp");
            sftpChannel.connect();
            if (isExistsDir(session, fileDir)) {
                // 获取文件列表
                Vector<ChannelSftp.LsEntry> files = sftpChannel.ls(StrUtil.removeAll(filePath, fileName));
                for (ChannelSftp.LsEntry file : files) {
                    SftpATTRS attrs = file.getAttrs();
                    if (!attrs.isDir() && fileName.equals(file.getFilename())){
                        isExists = true;
                    }
                }
            } else {
                isExists = false;
            }
            return isExists;
        } catch (Exception e) {
            log.error("校验文件夹是否存在异常" + e.getMessage());
            throw new RuntimeException("校验文件夹是否存在异常" + e.getMessage());
        } finally {
            sftpChannel.disconnect();
        }
    }

    /**
     * @Method renameFile
     * @Param
     * @Return void
     * @Description 重命名文件
     * @Author Wang zhihao
     * @Date 2023/11/21 19:12
     * @Version V1.0
     */
    @Override
    public void renameFile(Session session, String oldFilePath, String newFilePath) {
        Channel channel = null;
        ChannelSftp sftpChannel = null;
        try {
            channel = session.openChannel("sftp");
            channel.connect();
            sftpChannel = (ChannelSftp) channel;
            sftpChannel.rename(oldFilePath, newFilePath);
        } catch (Exception e) {
            log.error("重命名文件异常" + e.getMessage());
            throw new RuntimeException("重命名文件异常" + e.getMessage());
        } finally {
            sftpChannel.exit();
            channel.disconnect();
        }
    }

    /**
     * @Method copyFileLocal
     * @Param
     * @param session
     * @param sourceDir
     * @param targetDir
     * @Return void
     * @Description 本地复制文件到指定路径
     * @Author Wang zhihao
     * @Date 2024/1/26 11:28
     * @Version V1.0
     */
    @Override
    public void copyFileLocal(Session session, String sourceDir, String targetDir) {
        if (!isExistsDir(session, targetDir)) {
            createDir(session, targetDir);
        }
        String command = StrUtil.format("scp -r {} {}", sourceDir, targetDir);
        executeCommand(session, command);
    }

    /**
     * @Method chmodDir
     * @Param
     * @param session
     * @param targetDir
     * @Return void
     * @Description 更改指定目录权限
     * @Author Wang zhihao
     * @Date 2024/1/26 11:28
     * @Version V1.0
     */
    @Override
    public void chmodDir(Session session, String targetDir, String user) {
        String command = StrUtil.format("chown -R {}:{} {}", user, user, targetDir);
        executeCommand(session, command);
    }

    private void executeCommand(Session session, String command){
        try {
            ChannelExec channel = (ChannelExec) session.openChannel("exec");
            channel.setCommand(command);

            InputStream in = channel.getInputStream();
            channel.connect();

            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            channel.disconnect();
        } catch (Exception e) {
            log.error("执行SCP命令异常：{}", e.getMessage(), e);
            throw new RuntimeException("执行SCP命令异常: " + e.getMessage(), e);
        }
    }
}
